﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ArivisTests.Models;

namespace ArivisTests.Controllers
{
    [Authorize]
    public class AssignTestController : Controller
    {
        private ArivisTestsDBContext db = new ArivisTestsDBContext();

        //
        // GET: /AssignTest/Manual/5
        public ActionResult Manual(int id, int? page)
        {
            TestRun dbTestRun = db.TestRunsWithDetails.FirstOrDefault(run => run.Id == id);
            if (dbTestRun == null)
            {
                return HttpNotFound();
            }

            return View(dbTestRun);
        }

        void initPaging(TestRun dbTestRun, int? page)
        {
            int pageSize = 15;
            int testCount = dbTestRun.Tests.Count();
            int pageCount = testCount / pageSize;
            if (testCount % pageSize > 0) pageCount++;

            ViewBag.Page = page.GetValueOrDefault();
            ViewBag.PageSize = pageSize;
            ViewBag.PageCount = pageCount;
            ViewBag.TestCount = testCount;
        }

        [HttpPost]
        public ActionResult Manual(int id, FormCollection form)
        {
            var dbTestRun = db.TestRunsWithDetails.First(x => x.Id == id);

            foreach (var key in form.AllKeys.Where(key => key.StartsWith("user_")))
            {
                // get dbUser for this
                int userId = Int32.Parse(key.Substring(5));
                var dbUser = db.ActiveTester.FirstOrDefault(user => user.UserId == userId);

                // get all test cases assigned to this user
                int[] testCaseIds = ParseTestCaseIds(form[key]);
                var userTests = dbTestRun.Tests.Where(test => testCaseIds.Contains(test.Id));

                // make use all selected tests are assigned to this user
                foreach (var test in userTests.Where(test => test.User != dbUser))
                {
                    test.User = dbUser;
                }

                // update test order
                foreach (var test in userTests)
                {
                    test.Order = Array.IndexOf(testCaseIds, test.Id);
                }
            }

            db.SaveChanges();
            return View(dbTestRun);
        }

        int[] ParseTestCaseIds(string value)
        {
            if (string.IsNullOrEmpty(value)) 
                return new int[0];
            
            return value.Split(';').Select(x => Int32.Parse(x)).ToArray();
        }

        //
        // GET: /AssignTest/Automatic/5
        public ActionResult Automatic(int id)
        {
            TestRun testrun = db.TestRuns.Find(id);
            ViewBag.Tester = db.ActiveTester.ToList().Select(user => new SelectListItem() { Value = user.UserId.ToString(), Text = user.UserName });
            if (testrun == null)
            {
                return HttpNotFound();
            }
            return View(testrun);
        }

        [HttpPost]
        public ActionResult Automatic(int id, FormCollection form)
        {
            // get test run
            TestRun dbTestRun = db.TestRuns.Find(id);

            // get test user
            List<AssignmentUser> assignedUsers = new List<AssignmentUser>();
            foreach (var key in form.AllKeys.Where(key => key.StartsWith("user_")))
            {
                int userId;
                int available;
                if (!Int32.TryParse(key.Substring(5), out userId)) continue;
                if (form[key] == "false") continue;
                if (!Int32.TryParse(form["available_" + userId], out available)) continue;
                var dbUser = db.ActiveTester.FirstOrDefault(x => x.UserId == userId);
                if (dbUser == null) continue;
                assignedUsers.Add(new AssignmentUser() { UserProfile = dbUser, Available = available });
            }

            // get test scenarios
            List<AssignmentScenario> assignTests = new List<AssignmentScenario>();
            foreach (var key in form.AllKeys.Where(key => key.StartsWith("count_")))
            {
                int scenarioId;
                int count;
                if (!Int32.TryParse(key.Substring(6), out scenarioId)) continue;
                if (!Int32.TryParse(form[key], out count)) continue;

                var scenario = db.TestScenarios.FirstOrDefault(x => x.Id == scenarioId);
                if (scenario == null) continue;
                assignTests.Add(new AssignmentScenario() { Scenario = scenario, Runs = count });
            }

            // create/remove test cases
            foreach (var assignTest in assignTests)
            {
                var testCases = dbTestRun.Tests.Where(x => x.Scenario == assignTest.Scenario).ToList();
                while (testCases.Count > assignTest.Runs)
                {
                    TestCase removeCase = testCases.Last();
                    dbTestRun.Tests.Remove(removeCase);
                    testCases.Remove(removeCase);
                }
                while (testCases.Count < assignTest.Runs)
                {
                    TestCase newCase = TestCase.Create(db, assignTest.Scenario);
                    dbTestRun.Tests.Add(newCase);
                    testCases.Add(newCase);
                }
                assignTest.Tests = testCases;
            }

            // calculate assignments
            var assignments = AssignTestImpl.AssignTester(assignedUsers, assignTests);

            // update test cases
            foreach (var assignment in assignments)
            {
                for (int i = 0; i < assignment.Tests.Count; i++)
                {
                    AssignmentCase assignmentCase = assignment.Tests[i];
                    assignmentCase.TestCase.User = assignment.UserProfile;
                    assignmentCase.TestCase.Order = i;
                }
            }

            db.SaveChanges();
            return RedirectToAction("Details", "TestRun", new { id = dbTestRun.Id });
        }

        //
        // GET: /AssignTest/AddTest/5
        public ActionResult AddTest(int? id)
        {
            // get original test case
            var testCase = db.TestCases.First(x => x.Id == id);
            var newTestCase = TestCase.Create(db, testCase.Scenario);
            var testRun = testCase.Run;
            testRun.Tests.Add(newTestCase);

            db.SaveChanges();

            return RedirectToAction("Manual", new { id = testRun.Id });
        }

        //
        // GET: /AssignTest/RemoveTest/5
        public ActionResult RemoveTest(int? id)
        {
            // get original test case
            var testCase = db.TestCases.First(x => x.Id == id);
            var testRun = testCase.Run;
            db.TestCases.Remove(testCase);

            db.SaveChanges();

            return RedirectToAction("Manual", new { id = testRun.Id });
        }

        [HttpPost]
        public ActionResult AddScenario(int id, int? scenario, int? user)
        {
            TestRun dbTestRun = db.TestRuns.First(t => t.Id == id);
            TestScenario dbTestScenario = db.TestScenarios.First(s => s.Id == scenario);
            UserProfile dbUser = db.ActiveTester.FirstOrDefault(u => u.UserId == user);

            TestCase newCase = TestCase.Create(db, dbTestScenario);
            newCase.User = dbUser;
            dbTestRun.Tests.Add(newCase);

            db.SaveChanges();
            return RedirectToAction("Manual", new { id = dbTestRun.Id });
        }

        protected override void Dispose(bool disposing)
        {
            db.Dispose();
            base.Dispose(disposing);
        }
    }
}
